//==================================================================
//  Copyright (C) 2006  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
/// @file m5d_displist_vpool.cpp
///
///
///
//==================================================================

#include "stdafx.h"
#include "m5d_displist_vpool.h"

//==================================================================
using namespace M5D;

//==================================================================
//==
//==================================================================
DListVertPool::DListVertPool( const DListVertPool *src_objp )
{
	_n_verts = 0;	// will be set by AllocateData()
	_stride = src_objp->_stride;
	_size = src_objp->_size;

	for (int i=0; i < VType::N; ++i)
	{
		_datap[i] = NULL;	// pointers are built by AllocateData()
		_byte_offs[i] = src_objp->_byte_offs[i];
		_formats[i] = src_objp->_formats[i];
		_sizes[i] = src_objp->_sizes[i];
	}

	AllocateData( src_objp->_n_verts );
	memcpy( _datap[0], src_objp->_datap[0],  _n_verts * _stride );
}

//==================================================================
const int	DListVertPool::_vformat_size_table[FORMAT_N] =
{
	0,				// FORMAT_EMPTY
	sizeof(float),	// FORMAT_FLOAT
	sizeof(u_char)	// FORMAT_BYTE	
};

//==================================================================
const int	DListVertPool::_vert_count_table[VType::N] =
{
	3,	// pos
	2,	// tex
	4,	// col
	3	// nor
};

//==================================================================
void DListVertPool::AddItem( u_int format, VType::VType usage )
{
	int	i = usage;
	_byte_offs[i] = _stride;
	_formats[i] = format;

	_sizes[i] = CalcVertSize( usage, format );
	_stride += _sizes[i];
	_size += _sizes[i];
}

//==================================================================
void DListVertPool::AllocateData( int n_verts ) throw(...)
{
	FreeData();

	if ( n_verts <= 0 || _stride <= 0 )
		return;

	_datap[0] = (u_char *)PSYS_MALLOC( n_verts * _stride );
	_n_verts = n_verts;

	for (int i=1; i < VType::N; ++i)
	{
		if ( _formats[i] != FORMAT_EMPTY )
		{
			_datap[i] = (u_char *)_datap[0] + _byte_offs[i];
		}
	}
}

//==================================================================
void DListVertPool::CopyVert( int vidx, VType::VType usage, const void *src_datap, u_int src_format )
{
	PASSERT( vidx >= 0 && vidx < _n_verts );

	u_char	*desp = (u_char *)GetVertPtr( vidx, usage );

	if ( _formats[usage] == src_format )
	{
		memcpy( desp, src_datap, _sizes[usage] );
	}
	else
	{
		int		count = _vert_count_table[ usage ];

		switch ( _formats[usage] )
		{
		case FORMAT_FLOAT:
			if ( src_format == FORMAT_BYTE )
			{
				for (int i=0; i < count; ++i)
					((float *)desp)[i] = ((u_char *)src_datap)[i] * (1.0f/255);
			}
			else
			{	// shouldn't really happen !!!
				PASSERT( 0 );
			}
			break;

		case FORMAT_BYTE:
			if ( src_format == FORMAT_FLOAT )
			{
				for (int i=0; i < count; ++i)
					((u_char *)desp)[i] = ((float *)src_datap)[i] * 255;
			}
			else
			{	// shouldn't really happen !!!
				PASSERT( 0 );
			}
			break;

		default:
			PASSERT( 0 );
			break;
		}
	}
}


//==================================================================
void DListVertPool::FreeData()
{
	SAFE_FREE( _datap[0] );
	for (int i=0; i < VType::N; ++i)
		_datap[i] = NULL;

	_n_verts = 0;
}

//==================================================================
void DListVertPool::Reset()
{	// reset everything.. but doen't touch the main memory pointer !
	// that is to be dealt with only at constructor time and alloc/free operations
	// blindly zeroing the memory pointer isn't a very good idea
	_n_verts = 0;
	_stride = 0;
	_size = 0;
	for (int i=0; i < VType::N; ++i)
	{
		_byte_offs[i] = 0;
		_formats[i] = FORMAT_EMPTY;
		_sizes[i] = 0;
	}
	for (int i=1; i < VType::N; ++i)
		_datap[i] = NULL;
}

//==================================================================
void DListVertPool::CopyDefinitions( const DListVertPool &from )
{
	for (int i=0; i < VType::N; ++i)
	{
		_byte_offs[i]	= from._byte_offs[i];
		_formats[i]		= from._formats[i];
		_sizes[i]		= from._sizes[i];
	}
	_stride	= from._stride;
	_size	= from._size;
}
